home *** CD-ROM | disk | FTP | other *** search
/ Internet Publisher's Toolbox 2.0 / Internet Publisher's Toolbox.iso / internet / ntserver / wtsource / sersrch.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-23  |  35.1 KB  |  1,128 lines

  1. /* WIDE AREA INFORMATION SERVER SOFTWARE
  2.    No guarantees or restrictions.  See the readme file for the full standard
  3.    disclaimer.    
  4.    Brewster@think.com
  5. */
  6.  
  7. /* Copyright (c) CNIDR (see ../COPYRIGHT) */
  8.  
  9. /* implements the search part of irext.h 
  10.    (search_word and finished_search_word)
  11.    -brewster
  12.  
  13. Split from irsearch.c
  14.  
  15.    5/31/91 Added scale_scores.  Fixed document_score_array to long.
  16.    7/8/91 Removed scale_scores, handled in search_word with doc_id > 0.
  17.    2/4/92 Made document_score_array a double.
  18.  
  19.    - Jonny G
  20.  * $Log:    sersrch.c,v $
  21.  * Revision 1.33  93/07/21  18:47:38  warnock
  22.  * Added STELAR-specific patches
  23.  *
  24.  * Revision 1.10  1993/10/13  14:14:20  huynh1
  25.  * new code added for encapsulated boolean queries and
  26.  * modified literal search
  27.  * 
  28.  * Revision 1.32  93/07/19  17:09:39  warnock
  29.  * fixed problem with multiple documents in single file, from isaacs@hpcc05.corp.hp.com
  30.  *
  31.  * Revision 1.3  1993/07/13  08:19:56  pfeifer
  32.  * Sicherung vor Aenderungen Tung
  33.  * 
  34.  * Revision 1.31  93/07/02  18:31:06  warnock
  35.  * included ctype.h
  36.  * 
  37.  * Revision 1.3a  93/07/02  17:59:25  warnock
  38.  * change to search_word to handle compressed files from francois
  39.  * 
  40.  * Revision 1.1  1993/02/16  15:05:35  freewais
  41.  * Initial revision
  42.  *
  43.  * Revision 1.24  92/04/28  16:56:54  morris
  44.  * added boolean to serial engine
  45.  * 
  46.  * Revision 1.23  92/03/15  10:15:18  jonathan
  47.  * Added Simon Spero's ASSIGN replacement for read_bytes.
  48.  * 
  49.  * Revision 1.22  92/03/05  07:09:54  shen
  50.  * add two more dummy arguments to call to init_search_engine
  51.  * 
  52.  * Revision 1.21  92/02/12  17:29:52  jonathan
  53.  * Conditionalized inclusion of object code.
  54.  * 
  55.  * Revision 1.20  92/02/12  13:40:06  jonathan
  56.  * Added "$Log" so RCS will put the log message in the header
  57.  * 
  58. */
  59.  
  60. #include <string.h>
  61. #include "cdialect.h"
  62. #include "irfiles.h"
  63. #ifdef BIO
  64. #include "irtfiles.h" /* dgg, for wordDelimiter */
  65. #endif /* BIO */
  66. #include "irsearch.h"
  67. #include "irext.h"
  68. #include "byte_order.h"
  69. #include <ctype.h>
  70.  
  71. #include <math.h>
  72.  
  73. /* tung, 10/93 */
  74. #ifdef BOOLEANS
  75. #include "boolean_op.h"
  76. #endif /* BOOLEANS */
  77. /* tung, 10/93 */
  78.  
  79. /* #define MAXINT (unsigned long)2^(sizeof(long)*8-1) */
  80.  
  81. #define VALUE 1000000L
  82.  
  83. #include "stemmer.h"   
  84.  
  85. /* tung, 10/93 */
  86. #ifdef BOOLEANS
  87. #include "boolean_op.h"
  88. #endif /* BOOLEANS */
  89. /* tung, 10/93 */
  90.  
  91. #ifdef BOOL
  92. #include "obj.h"
  93. #include "irparse.h"
  94. object* currentQuery = NULL; /* kludge until irext goes away */
  95. #endif /* def BOOL */
  96.  
  97. #ifdef WIN32
  98. #include <io.h>
  99. #endif
  100.  
  101. /* weighting for relevant document terms - 
  102.    this may become a parameter to the query.
  103. */
  104.  
  105. #define RF_WEIGHTING 0.1
  106.  
  107. /* ==================================
  108.  * ===  Initialization Functions  ===
  109.  * ==================================*/
  110.  
  111.  
  112. long init_search_engine(file, initialize, for_search, cm_mem_percent, 
  113. text_size, grow_percent)
  114.   char* file;
  115.   boolean initialize;
  116.   boolean for_search;
  117.   long cm_mem_percent;  /* unused */
  118.   long text_size;     /* unused */
  119.   long grow_percent;  /* unused */
  120. {
  121.   static boolean inited = false;
  122.  
  123.   if (inited == false)
  124.    { 
  125. #ifdef BOOL
  126.      initObj();
  127.      initBool();
  128. #endif /* BOOL */
  129.      inited = true;
  130.    }
  131.  
  132.   return(0);
  133. }
  134.  
  135. long finished_search_engine()
  136. {
  137.   return(0);
  138. }
  139.  
  140.  
  141. /*
  142.  *  ext_open_database: see irext.h
  143.  */
  144.  
  145. long ext_open_database (db, initialize, for_search)
  146.      database *db;
  147.      boolean initialize;
  148.      boolean for_search;
  149. { /* this has to deal with the .inv file */
  150.   char file[MAX_FILE_NAME_LEN];
  151.  
  152.   if(initialize) /* make a new one */
  153.     db->index_stream = s_fopen(index_filename(file, db), "w+b");
  154.   else if(for_search) /* just search */
  155.     db->index_stream = s_fopen(index_filename(file, db), "rb");
  156.   else /* write to an existing db */
  157.     db->index_stream = s_fopen(index_filename(file, db), "r+b");
  158.  
  159.   if (db->index_stream == NULL) {
  160.     waislog(WLOG_HIGH, WLOG_ERROR,"2can't open the inverted index file %s\n", 
  161.         file);
  162.       disposeDatabase(db);
  163.       return(1);
  164.     }
  165.   return(0);
  166. }
  167.   
  168.  
  169.  
  170. /*
  171.  *  ext_close_database: see irext.h
  172.  */
  173.  
  174. long ext_close_database (db)
  175.      database *db;
  176. {
  177.   return(0);
  178. }
  179.  
  180. char *database_file(database_name)
  181.      char *database_name;
  182. {
  183.   return(database_name);
  184. }
  185.   
  186. /*===========================*
  187.  *===  Setting Paramters  ===*
  188.  *===========================*/
  189.  
  190. long max_hit_retrieved = 0;
  191. char **srcs = NULL;
  192.  
  193. long set_query_parameter (mask, parameters)
  194.      long mask;
  195.      query_parameter_type * parameters;
  196. {
  197.   switch (mask)
  198.     {
  199.     case SET_MAX_RETRIEVED_MASK:
  200.       max_hit_retrieved = parameters->max_hit_retrieved;
  201.       return(0);
  202.       break;
  203.     case SET_SELECT_SOURCE:
  204.       if(NULL != srcs){
  205.     if(NULL != srcs[0])
  206.       s_free(srcs[0]);
  207.     s_free(srcs);
  208.       }
  209.       srcs = parameters->srcs;
  210.       break;
  211.     default:
  212.       return(-1);
  213.       break;
  214.     }
  215.   return(0);
  216. }
  217.  
  218. /*==============================*
  219.  *===  Document Score Array  ===*
  220.  *==============================*/
  221.  
  222. double *document_score_array = NULL;
  223. long document_score_array_len = 0;
  224. #ifdef BOOLEANS
  225. double *prev_score_array = NULL;                    /* 12/91 GS TLG */
  226.  
  227. /* tung, 10/93 */
  228. search_result_struct *search_result_array = NULL;
  229. /* tung, 10/93 */
  230.  
  231. #endif /* BOOLEANS */
  232.  
  233. /* make_document_score_array insures that the document_score_array
  234.    array is long enough, if not it makes it long enough */
  235. static void make_document_score_array _AP((long length ));
  236. static void make_document_score_array(length)
  237. long length;
  238. {
  239.   if(length <= document_score_array_len)
  240.     return;
  241.   /* we have to make a new one.  free the old one first (if any) */
  242.   if(document_score_array != 0){
  243.     s_free(document_score_array);
  244. #ifdef BOOLEANS
  245.     s_free(prev_score_array);                   /* 12/91 GS TLG */
  246. #endif /* BOOLEANS */
  247.   }
  248.   document_score_array = (double*)s_malloc(
  249.                      (size_t)(length * sizeof(double)));
  250. #ifdef BOOLEANS
  251.   prev_score_array   = (double*)s_malloc((size_t)(length * sizeof(double)));  /* 12/91 GS TLG */
  252. #endif /* BOOLEANS */
  253.   document_score_array_len = length;
  254. }
  255.  
  256. static void destroy_document_score_array _AP((void));
  257. static void destroy_document_score_array()
  258. {
  259.   s_free(document_score_array);
  260. #ifdef BOOLEANS
  261.   s_free(prev_score_array);                 /* 12/91 GS TLG */
  262. #endif /* BOOLEANS */
  263.   document_score_array_len = 0;
  264. }
  265.     
  266. void clear_document_score_array()
  267. /* side effects the document_score_array. */
  268.   memset(document_score_array, 0, 
  269.      document_score_array_len * sizeof(double));
  270. #ifdef BOOLEANS
  271.   memset(prev_score_array, 0,                   /* 12/91 GS TLG */
  272.          document_score_array_len * sizeof(double));        /* 12/91 GS TLG */
  273. #endif /* BOOLEANS */
  274. }
  275.  
  276. /* for debugging purposes */
  277. void print_document_score_array(start,stop)
  278. unsigned long start;
  279. unsigned long stop;
  280. /* assumes start >= 0, stop < db->doc_table_allocated_entries */
  281. {
  282.     long i;
  283. #ifdef WIN32
  284.     for(i = start; i <= (long)stop; i++){
  285. #else
  286.     for(i = start; i <= stop; i++){
  287. #endif
  288.         printf("entry number %d: %f \n", 
  289.                i, document_score_array[i]);
  290.     }
  291. }
  292.  
  293.  
  294.  
  295. /*=========================*
  296.  *===  Best Hits Array  ===*
  297.  *=========================*/
  298.  
  299. hit *best_hits_array = NULL;
  300. long best_hits_array_len = 0;
  301. long current_best_hit = 0;
  302.  
  303. /* see irext.h for doc */
  304. long init_best_hit (db)
  305.      database *db;
  306. {
  307.  
  308. #ifdef BOOL
  309.   if (currentQuery != NULL)
  310.     send(currentQuery,InitBestHit,db);
  311. #endif /* def BOOL */
  312.  
  313.   return(0);
  314. }
  315.  
  316. /* make_best_hits_array insures that the best_hits_array
  317.    array is long enough, if not it makes it long enough */
  318. static void make_best_hits_array _AP((long length));
  319. static void make_best_hits_array(length)
  320. long length;
  321. {
  322.   if(length <= best_hits_array_len)
  323.     return;
  324.   /* we have to make a new one.  free the old one first (if any) */
  325.   if(best_hits_array != 0){
  326.     s_free(best_hits_array);
  327.   }
  328.   best_hits_array = (hit*)s_malloc((size_t)(length * sizeof(hit)));
  329.   best_hits_array_len = length;
  330. }
  331.  
  332. static void destroy_best_hits_array _AP((void));
  333. static void destroy_best_hits_array()
  334. {
  335.   s_free(best_hits_array);
  336.   best_hits_array_len = 0;
  337. }
  338.     
  339. void clear_best_hits_array()
  340. /* side effects the best_hits_array.  XXX could use memset */
  341.   memset((char*)best_hits_array, 0, best_hits_array_len * sizeof(hit));
  342. }
  343.  
  344. /* for debugging purposes */
  345. void print_best_hits()
  346. {
  347.   long i;
  348.   for( i = 0; i < best_hits_array_len; i++){
  349.     if (best_hits_array[i].weight != 0)
  350.       { printf("Best hit %ld: weight %lf, doc_id %ld, headline %s, filename %s, lines %ld\n", 
  351.            i, best_hits_array[i].weight, 
  352.            best_hits_array[i].document_id,
  353.            best_hits_array[i].headline,
  354.            best_hits_array[i].filename,
  355.            best_hits_array[i].number_of_lines);
  356.       }
  357.   }
  358. }
  359.  
  360. void sort_best_hits(db)
  361.      database * db;
  362. {
  363.   /* returns nothing.
  364.    * side effects best_hits and document_score_array
  365.    */
  366.  
  367.   long i, doc;
  368.   double worst_weight_to_make_it = 0.0;
  369.   document_table_entry doc_entry;
  370.   long best_hit_number = 0;
  371.  
  372.   /* snuff the scores */
  373.   for(i = 0; i < max_hit_retrieved; i++){
  374.     best_hits_array[i].weight = 0.0;
  375.  
  376.   }
  377.  
  378.   /* loop over the doc, and keep the doc_id and weight in best hit table */
  379.   for(doc = 1; doc < db->doc_table_allocated_entries; doc++){
  380.     double weight = document_score_array[doc];
  381. /* jmf */
  382.     read_document_table_entry(&doc_entry, doc, db);  /* if this could be
  383. removed, we'd gain speed */
  384. /*      if (doc_entry.document_length) */
  385. #ifdef WIN32
  386.     /* Windows NT doesn't like dividing by 0.  This will cause the first
  387.        entry in the document table (which is a null entry) to be skipped.
  388.        [I don't understand why UNIX or the Macintosh don't have a problem here.]
  389.      */
  390.     if (doc_entry.document_length == 0) continue;
  391. #endif /* WIN32 */
  392.     weight/=doc_entry.document_length;
  393.     if(worst_weight_to_make_it < weight){
  394.       /* merge it into the best_hits array. start at the bottom */
  395.       for(i = (max_hit_retrieved - 1); i >= 0; i--){
  396.     if(weight > best_hits_array[i].weight 
  397.        /* && (check_document_id(doc, db) == true) too slow.*/
  398.        ){
  399.       /* move this entry down */    
  400.       if((i + 1) < max_hit_retrieved){
  401.         best_hits_array[i+1].weight = best_hits_array[i].weight;
  402.         best_hits_array[i+1].document_id = best_hits_array[i].document_id;
  403.       }
  404.       best_hits_array[i].document_id = doc;
  405.       best_hits_array[i].weight = weight;
  406.     }
  407.     else
  408.       break;
  409.       }      
  410.     }
  411.   }
  412.   
  413.   for(i = 0; i < max_hit_retrieved; i++){
  414.     if(best_hits_array[i].weight <= 0.0)
  415.       return;
  416.     if (read_document_table_entry(&doc_entry,
  417.                   best_hits_array[i].document_id,
  418.                   db) 
  419.     == true){
  420.       best_hits_array[best_hit_number].weight = best_hits_array[i].weight;
  421.  
  422.       best_hits_array[best_hit_number].document_id = best_hits_array[i].document_id;
  423.       best_hits_array[best_hit_number].start_character = doc_entry.start_character;
  424.       best_hits_array[best_hit_number].end_character = doc_entry.end_character;
  425.       best_hits_array[best_hit_number].document_length = doc_entry.document_length;
  426.       best_hits_array[best_hit_number].number_of_lines = doc_entry.number_of_lines;
  427.       sprintf(best_hits_array[best_hit_number].date, "%d", doc_entry.date);
  428.       read_filename_table_entry(doc_entry.filename_id, 
  429.                 best_hits_array[best_hit_number].filename,
  430.                 best_hits_array[best_hit_number].type,
  431.                 NULL,
  432.                 db),
  433.       strncpy(best_hits_array[best_hit_number].headline, 
  434.           read_headline_table_entry(doc_entry.headline_id,db),
  435.           MAX_FILE_NAME_LEN);
  436.       best_hit_number++;
  437.     } 
  438.     beFriendly();
  439.   }
  440.   for(i = best_hit_number; i < max_hit_retrieved; i++){
  441.     best_hits_array[best_hit_number].weight = 0.0;
  442.   }
  443.   /* print_best_hits(s);  for debugging */
  444. }
  445.  
  446.  
  447. /* returns the next best hit */
  448. long best_hit(db, doc_id, best_character, best_line, score,start,end,date,
  449. length,nlines,headline,filename,type)
  450.      database *db;
  451.      long *doc_id;  
  452.      long *best_character;
  453.      long *best_line;
  454.      double *score;
  455.     long *start,*end,*date,*length,*nlines;
  456. char *headline,*filename,*type;
  457. {
  458. double tmp;
  459.  
  460.   *best_character = 0; 
  461.   *best_line = 0;
  462.   
  463. #ifdef BOOL
  464.   if (currentQuery != NULL) /* for boolean */
  465.    {
  466.      send(currentQuery,GetBestHit,db,doc_id,best_character,best_line,score);
  467.      if (*doc_id > 0)
  468.        return(0); /* ok */
  469.      else
  470.        return(-1); /* no more docs */
  471.    }
  472. #endif /* BOOL */
  473.  
  474.   if(current_best_hit > best_hits_array_len)
  475.     return(1);
  476.   if(best_hits_array[current_best_hit].weight == 0.0)
  477.     return(1);
  478.   *doc_id = best_hits_array[current_best_hit].document_id;
  479.   tmp  = ((double)(best_hits_array[current_best_hit].weight*VALUE));
  480. *score=tmp;
  481. *start=best_hits_array[current_best_hit].start_character;
  482. *end=best_hits_array[current_best_hit].end_character;
  483. *date=atoi(best_hits_array[current_best_hit].date);
  484. *length=best_hits_array[current_best_hit].document_length;
  485. *nlines=best_hits_array[current_best_hit].number_of_lines;
  486. strcpy(headline,best_hits_array[current_best_hit].headline);
  487. strcpy(filename,best_hits_array[current_best_hit].filename);
  488. strcpy(type,best_hits_array[current_best_hit].type);
  489.   current_best_hit++;
  490.   return(0);
  491. }
  492.  
  493. long finished_best_hit(db)
  494. database *db;
  495.  
  496. #ifdef BOOL
  497.   if (currentQuery != NULL) /* for boolean */
  498.    { send(currentQuery,Delete);
  499.      currentQuery = NULL;
  500.      return(0);
  501.    }
  502. #endif /* BOOL */
  503.  
  504.   /* if we are on a small machine, we might want to 
  505.      destroy_document_score_array */
  506.   clear_document_score_array();
  507.   clear_best_hits_array();
  508.   current_best_hit = 0;
  509.   return(0);
  510. }
  511.  
  512. /*=============================*    
  513.  *===  Searching for words  ===*
  514.  *=============================*/
  515.  
  516. /* see irext.h for doc */
  517. long init_search_word (db)
  518.      database* db;
  519. {
  520. char fn[256];
  521.   strcpy( fn,db->database_file );
  522.   strcat( fn,synonym_ext );
  523.   syn_ReadFile( fn,&db->syn_Table,&db->syn_Table_Size );
  524.  
  525.   return(0);
  526. }
  527.  
  528.  
  529. #ifdef BOOLEANS
  530. /* tung, 10/93 */
  531. long word_id = 0;
  532. extern long number_of_qwords ;
  533. /* tung, 10/93 */
  534.  
  535. static boolean   gLastAnd= false;
  536. static boolean   gLastNot= false;
  537. #endif /* BOOLEANS */
  538.  
  539. /* see irext.h for doc */
  540. /* returns -1 if error, 1 if word exists, 0 if not */
  541.  
  542. long search_word(word,char_pos, line_pos, weight, doc_id, 
  543.          word_pair, db)
  544.      char *word; /* the word to be searched for */
  545.      long char_pos;     /* the position of the start of the word */
  546.      long line_pos;     /* is this needed? not for signature system */
  547.      long weight;       /* how important the word looks syntactically,
  548.                    such as is it bold */
  549.      long doc_id;       /* current document, seed words is 0,
  550.                    then it increments into the relevant 
  551.                    document */
  552.      long word_pair;
  553.      database *db;
  554. {
  555.   /* this side effects the document_score_array,
  556.    * and downcases the word.
  557.    * Returns 0 if successful or word not present, 
  558.    * returns non-0 if an error.
  559.    *
  560.    */
  561.   
  562.   long not_full_flag = INDEX_BLOCK_FULL_FLAG; /*start out full so it will go on looking */
  563.   long count, index_block_size;
  564.   long internal_document_id,  number_of_valid_entries;
  565.   double internal_weight;
  566.   long index_file_block_number;
  567.   long number_of_occurances;
  568.  
  569.   FOUR_BYTE index_buffer_data[INDEX_ELEMENT_SIZE*(1024/4)];
  570.   char *index_buffer;
  571.   char *i;
  572.   FILE *stream = NULL;
  573.  
  574.  
  575. #ifdef LITERAL
  576. #ifdef WIN32
  577.   long txt_pos;                   /* 2/92 GS TLG */
  578.   document_table_entry doc_entry;                   /* 2/92 GS TLG */
  579.   static FILE *txt_stream = NULL;                   /* 2/92 GS TLG */
  580. #else
  581.   long txt_pos, icnt, wcnt, pcnt;                   /* 2/92 GS TLG */
  582.   document_table_entry doc_entry;                   /* 2/92 GS TLG */
  583.   static FILE *txt_stream = NULL;                   /* 2/92 GS TLG */
  584.   char cmpr_word[MAX_PHRASE_LENGTH + 1];                /* 2/92 GS TLG */
  585.   char phrase[MAX_PHRASE_LENGTH + 1];                   /* 2/92 GS TLG */
  586. #endif
  587.   char txt_filename[MAX_FILENAME_LEN + 1];              /* 2/92 GS TLG */
  588.   char *temp_txt_filename = NULL;               
  589.   char prev_txt_filename[MAX_FILENAME_LEN + 1];             /* 2/92 GS TLG */
  590.   char txt_type[MAX_TYPE_LEN + 1];                  /* 2/92 GS TLG */
  591.   long phraselen= 0, txt_pos_fix= 0;
  592.   char *document_section = NULL;     /* tung , 10/93 */
  593.   long document_section_len = 0;     /* tung , 10/93 */
  594.   long phrase_readed = 0;            /* tung , 10/93 */
  595.   long phrase_count = 0;             /* tung , 10/93 */
  596.   boolean phrase_found = false;      /* tung , 10/93 */
  597. #endif /* LITERAL */
  598.   
  599. /* do synonym conversion */
  600.  
  601. /* in theory, one can replace a word with a boolean phrase */
  602. char *newword;
  603. double idf;
  604.  
  605.   newword = lookup_Synonym( word,db->syn_Table,db->syn_Table_Size );
  606. waislog(WLOG_HIGH,WLOG_INFO,"Word %s Syn %s",word,newword);
  607. strncpy(word,newword,MAX_WORD_LENGTH);
  608.  
  609. /* call the stemmer */
  610. #ifdef LITERAL
  611.   if (weight!=LITERAL_FLAG) {
  612.     stemmer(word); 
  613.   }
  614. #else
  615.   stemmer(word); 
  616. #endif /* LITERAL */
  617.  
  618. /* tung, 10/93 */
  619. #ifdef BOOLEANS
  620.   if(number_of_qwords > 0) {
  621.     if((weight!=LITERAL_FLAG) && IsOperator(word)) {
  622.       boolean_operations(word);
  623.       return(0);
  624.     }
  625.     if(search_result_array == NULL) {
  626.       search_result_array = 
  627.         (search_result_struct *)
  628.           s_malloc((size_t)(number_of_qwords * sizeof(search_result_struct))); 
  629.       word_id = 0;
  630.     }
  631.     if(strlen(word) == 1) {
  632.       search_result_array[word_id].number_of_hits = 0;
  633.       search_result_array[word_id].word_id = word_id;
  634.       save_word_id(word_id);
  635.       ++word_id;
  636.       return(0);
  637.     }
  638.   }
  639. #endif /* BOOLEANS */
  640. /* tung, 10/93 */
  641.   
  642.  
  643. #ifdef LITERAL
  644.   if (weight==LITERAL_FLAG) {
  645.     /* goto after_booleans */
  646. /* printf("search_word: literal word is [%s]\n", word); */
  647.     }
  648.   else 
  649. #endif /* LITERAL */
  650. #ifdef BOOLEANS
  651.   if (strcmp(word,BOOLEAN_AND)==0) {  /* should be all lowercase cmp here */
  652.     gLastAnd= true;
  653.     return(0);
  654.     }
  655.   else if (strcmp(word,BOOLEAN_NOT)==0) {  
  656.   /* ^^ this is bad if we intersperse "not"s in a query --
  657.      docs found after not word may include notted word --
  658.      need to go back to doing not words after others --
  659.      but need now to check for literal string first
  660.   */
  661.     gLastNot= true;
  662.     return(0);
  663.     }
  664.   if (weight == BOOLEAN_NOT_FLAG) gLastNot= true;
  665. #else
  666.      ;   /* if not LITERAL_FLAG */
  667. #endif /* BOOLEANS */
  668.  
  669.   index_buffer = (char*)index_buffer_data;
  670.  
  671. #ifdef LITERAL
  672.   if (weight==LITERAL_FLAG) {
  673.   /* note: we found the first word of phrase once in map_over_words, but i'm too lazy 
  674.     to put another parameter in that cascade of function calls it takes
  675.     to get here.
  676.   */
  677.     char  word1[MAX_WORD_LENGTH + 1];
  678.     register int i, len;
  679.     register boolean more;
  680.     phraselen= MIN( MAX_PHRASE_LENGTH, strlen(word));
  681.     len = MIN( MAX_WORD_LENGTH, phraselen);
  682.     for (i=0, more=true; i < len && more; ) {
  683.        word1[i] = word[i++];
  684. #ifdef BIO
  685.        more= (wordDelimiter(word[i]) == NOT_DELIMITER); 
  686. #else
  687.        more= (isalnum(word[i]));
  688. #endif /* BIO */
  689.        }
  690.     word1[i]= '\0';
  691.     txt_pos_fix= strlen(word1) + 1;
  692. /* printf("search_word: literal word1 is [%s]\n", word1); */
  693.     index_file_block_number = 
  694.      look_up_word_in_dictionary(word1, &number_of_occurances, db);
  695.     }
  696.   else
  697. #endif  /* LITERAL */
  698.  
  699. #ifdef PARTIALWORD
  700.   index_file_block_number = 
  701.     look_up_partialword_in_dictionary(word, &number_of_occurances, db);
  702. #else
  703.   index_file_block_number = 
  704.     look_up_word_in_dictionary(word, &number_of_occurances, db);
  705. #endif /* PARTIALWORD */
  706.  
  707.   current_best_hit = 0;  /* so that the best hits willstart from 0 */
  708.  
  709.   /* check the document_score_array */
  710.   if(document_score_array_len < db->doc_table_allocated_entries)
  711.     make_document_score_array(db->doc_table_allocated_entries);
  712.  
  713.   if(index_file_block_number >= 0){
  714. #ifdef PARTIALWORD
  715.    while(index_file_block_number > 0){  /* dgg, need 2nd loop here for multiple partwords */
  716. #endif /* PARTIALWORD */
  717.     stream = db->index_stream;
  718.     
  719.     while((not_full_flag != INDEX_BLOCK_NOT_FULL_FLAG) && 
  720.       (index_file_block_number != 0)){  
  721.       /* read the index block */
  722.       if (0 != fseek(stream, (long)index_file_block_number, 
  723.              SEEK_SET)) 
  724.     { 
  725.       waislog(WLOG_HIGH, WLOG_ERROR, 
  726.           "fseek failed into the inverted file to position %ld",
  727.           (long)index_file_block_number); 
  728. #ifdef BOOLEANS
  729.    gLastNot= gLastAnd= false;
  730. #endif /* BOOLEANS */  
  731.       return(-1);
  732.     }
  733. #ifdef WIN32
  734.       _read(fileno(stream),index_buffer,INDEX_BLOCK_HEADER_SIZE);
  735. #else
  736.  
  737.       fread(index_buffer, INDEX_BLOCK_HEADER_SIZE, 1, stream);
  738. #endif
  739.  
  740.       ASSIGN(not_full_flag,
  741.          INDEX_BLOCK_FLAG_SIZE,
  742.          index_buffer,
  743.          INDEX_BLOCK_HEADER_SIZE,
  744.          0 );
  745.       ASSIGN(index_file_block_number,NEXT_INDEX_BLOCK_SIZE,
  746.          index_buffer+INDEX_BLOCK_FLAG_SIZE,
  747.          INDEX_BLOCK_HEADER_SIZE,
  748.          INDEX_BLOCK_FLAG_SIZE);
  749.       ASSIGN(index_block_size,INDEX_BLOCK_SIZE_SIZE,
  750.          index_buffer+INDEX_BLOCK_FLAG_SIZE+NEXT_INDEX_BLOCK_SIZE,
  751.          INDEX_BLOCK_HEADER_SIZE,
  752.          INDEX_BLOCK_FLAG_SIZE+NEXT_INDEX_BLOCK_SIZE);
  753.  
  754. /*
  755.   this is equivalent, but slower:
  756.  
  757.       not_full_flag = read_bytes(INDEX_BLOCK_FLAG_SIZE, stream);
  758.       index_file_block_number = read_bytes(NEXT_INDEX_BLOCK_SIZE, stream);
  759.       index_block_size = read_bytes(INDEX_BLOCK_SIZE_SIZE, stream);
  760. */
  761.  
  762. /*  Jim's debug code commented out
  763.       printf("flag = %d, block_num = %d, block_size = %d\n",
  764.          not_full_flag, 
  765.          index_file_block_number,
  766.          index_block_size);
  767. */
  768.       fflush(stdout);
  769.  
  770.       if(EOF == index_block_size) 
  771.     { 
  772.       waislog(WLOG_HIGH, WLOG_ERROR, 
  773.           "reading from the index file failed");
  774. #ifdef BOOLEANS
  775.    gLastNot= gLastAnd= false;
  776. #endif /* BOOLEANS */  
  777.       return(-1);
  778.     }
  779.       
  780.       if(not_full_flag == INDEX_BLOCK_NOT_FULL_FLAG){
  781.     /* not full */
  782.     number_of_valid_entries = index_file_block_number;
  783.       }
  784.       else if(not_full_flag == INDEX_BLOCK_FULL_FLAG){
  785.     /* full */
  786.     number_of_valid_entries = index_block_size - INDEX_BLOCK_HEADER_SIZE;
  787.       }
  788.       else{         /* bad news, file is corrupted. */
  789.     waislog(WLOG_HIGH, WLOG_ERROR, 
  790.         "Expected the flag in the inverted file to be valid.  it is %ld",
  791.         not_full_flag);
  792. #ifdef BOOLEANS
  793.    gLastNot= gLastAnd= false;
  794. #endif /* BOOLEANS */  
  795.     return(-1);
  796.       }
  797.       /* printf("number of valid bytes: %ld\n", number_of_valid_entries); */
  798.       
  799.       /* add the array to the document_score_array */
  800.       number_of_valid_entries /= INDEX_ELEMENT_SIZE;
  801.  
  802.  
  803. /* tung, 10/93 */
  804. #ifdef BOOLEANS   
  805.       if((number_of_qwords > 0) && (search_result_array != NULL)) {
  806.         if(search_result_array[word_id].doc_ids_array == NULL) 
  807.           search_result_array[word_id].doc_ids_array =
  808.             (doc_descr_struct *)
  809.               s_malloc((size_t)(sizeof(doc_descr_struct) * number_of_valid_entries));
  810.         search_result_array[word_id].number_of_hits = number_of_valid_entries;
  811.       }
  812. #endif /* BOOLEANS */
  813. /* tung, 10/93 */
  814.  
  815.  
  816. /* ses - idf is a fist approximation to the inverse document freq. */
  817. /* what it actually is  is the inverse occurance frequency which says
  818. that the significance of a word is inversly proportional to the number
  819. of times it occurs in the database */
  820.  
  821.     idf=1.0/number_of_occurances; 
  822.       for(count=0;count <  number_of_valid_entries;count++) {
  823.     int wgt;
  824.     int did;
  825. /*
  826.     if(count%1024 == 0) {
  827.       read(fileno(stream),index_buffer,INDEX_ELEMENT_SIZE*
  828.         MIN(1024,number_of_valid_entries-count));
  829.       i=index_buffer;
  830.     }
  831. */
  832.     did = read_bytes(DOCUMENT_ID_SIZE, stream);
  833.         (void)read_bytes(WORD_POSITION_SIZE, stream);
  834.         txt_pos=read_bytes(CHARACTER_POSITION_SIZE, stream);
  835.         wgt = read_bytes(WEIGHT_SIZE,stream);
  836. /*
  837.  
  838.     ASSIGN(wgt,WEIGHT_SIZE,    
  839.            i+DOCUMENT_ID_SIZE+WORD_POSITION_SIZE+CHARACTER_POSITION_SIZE,
  840.            INDEX_ELEMENT_SIZE,
  841.            DOCUMENT_ID_SIZE+WORD_POSITION_SIZE+CHARACTER_POSITION_SIZE);
  842.     ASSIGN(did,DOCUMENT_ID_SIZE,i,INDEX_ELEMENT_SIZE,0);
  843. */
  844. #ifdef LITERAL
  845.     /* dgg -- is this proper update of read form to ASSIGN form ??*/
  846.     /* txt_pos = read_bytes(CHARACTER_POSITION_SIZE, stream);*/     /* 2/92 GS TLG */
  847.         if ((weight == LITERAL_FLAG) && (0 == doc_id))  {        
  848. /*
  849.     ASSIGN(txt_pos,CHARACTER_POSITION_SIZE,i+DOCUMENT_ID_SIZE+WORD_POSITION_SIZE,
  850.         INDEX_ELEMENT_SIZE,DOCUMENT_ID_SIZE+WORD_POSITION_SIZE);
  851. */
  852. /* printf("search_word: txtpos=%d, wgt=%d, did=%d\n", txt_pos, wgt, did); */
  853.         }
  854. #endif /* LITERAL */
  855.  
  856. /* Commented out as suggested by Stan Isaacs at hp.com to come up with correct
  857.  * weights when there are multiple documents in a file
  858.  *
  859.  *  if(wgt>5L)
  860.  *      wgt-=5L;
  861.  */
  862.     internal_weight = log((double)wgt);
  863.     internal_weight+=10.0;
  864.     internal_document_id = did;
  865.  
  866. /*
  867.     printf("entry %ld, Doc_id: %ld, weight %lf \n",
  868.         count, internal_document_id, internal_weight);
  869.     fflush(stdout);
  870. */
  871.     if(EOF == wgt) 
  872.       { 
  873.         waislog(WLOG_HIGH, WLOG_ERROR, 
  874.             "reading from the doc-id table failed");
  875. #ifdef BOOLEANS
  876.    gLastNot= gLastAnd= false;
  877. #endif  /* BOOLEANS */
  878.         return(-1);
  879.       }
  880.  
  881. #ifdef LITERAL         
  882.         if ((weight == LITERAL_FLAG) && (0 == doc_id)) {        /* 2/92 GS TLG */
  883.           if (true == read_document_table_entry(&doc_entry,     /* 2/92 GS TLG */
  884.                                              internal_document_id, db)) /* 2/92 GS TLG */
  885.        {                                /* 2/92 GS TLG */
  886.             read_filename_table_entry(doc_entry.filename_id,        /* 2/92 GS TLG */
  887.                                       txt_filename, txt_type, NULL, db);  /* 2/92 GS TLG */
  888. /* printf("search_word: document is [%s]\n", txt_filename); */
  889.             if (NULL == txt_stream) {
  890.               if (probe_file(txt_filename)) {
  891.                 txt_stream = s_fopen(txt_filename, "rb");
  892.               }
  893.               else if (probe_file_possibly_compressed(txt_filename)) {
  894.                temp_txt_filename = s_fzcat(txt_filename);
  895.                if (temp_txt_filename) {
  896.             txt_stream = s_fopen(temp_txt_filename, "rb");
  897.            }
  898.           }
  899.           
  900.               strcpy(prev_txt_filename, txt_filename);
  901.             }
  902.             else if (0 != strcmp(txt_filename, prev_txt_filename)) {
  903.               s_fclose(txt_stream);
  904.               if ( temp_txt_filename != NULL ) {
  905.                 unlink(temp_txt_filename);
  906.                 s_free(temp_txt_filename);
  907.               }
  908.               if (probe_file(txt_filename)) {
  909.                 txt_stream = s_fopen(txt_filename, "rb");
  910.               }
  911.               else if (probe_file_possibly_compressed(txt_filename)) {
  912.                temp_txt_filename = s_fzcat(txt_filename);
  913.                if (temp_txt_filename) {
  914.             txt_stream = s_fopen(temp_txt_filename, "rb");
  915.             }
  916.           }
  917.               strcpy(prev_txt_filename, txt_filename);      /* 2/92 GS TLG */
  918.             }
  919.  
  920.             txt_pos += doc_entry.start_character - txt_pos_fix;  /* dgg */
  921.  
  922.             document_section_len = doc_entry.end_character - txt_pos;   /* tung, 10/93 */
  923.             s_fseek(txt_stream, txt_pos, SEEK_SET);                     /* 2/92 GS TLG */
  924.             document_section = 
  925.               (char*) s_malloc((size_t)((document_section_len+1)*sizeof(char))); /* tung, 10/93 */
  926.             fgets(document_section, document_section_len, txt_stream);   /* tung, 10/93 */
  927.             phrase_readed = 0;                                           /* tung, 10/93 */
  928.             phrase_readed += strlen(document_section);                   /* tung, 10/93 */
  929.             document_section = string_downcase(document_section);        /* tung, 10/93 */
  930. #if 0
  931.  
  932.             fread(phrase, 1L, phraselen, txt_stream);                   /* 2/92 GS TLG */
  933. /* { phrase[phraselen]= '\0';
  934. printf("search_word: file phrase is [%s]\n", phrase); 
  935. } */
  936. #ifdef WIN32
  937.             if (0 != _strnicmp(word, phrase, phraselen))      /* 2/92 GS TLG */
  938. #else
  939.             if (0 != strncasecmp(word, phrase, phraselen))      /* 2/92 GS TLG */
  940. #endif
  941.               internal_weight = 0.0;                    /* 2/92 GS TLG */
  942. #endif  /* 0 */
  943.  
  944.             if (NULL == strstr(document_section, word)) {                    /* tung, 10/93 */
  945.               while(phrase_readed < document_section_len) {                  /* tung, 10/93 */
  946.                 fgets(document_section, document_section_len, txt_stream);   /* tung, 10/93 */
  947.                 phrase_readed += strlen(document_section);                   /* tung, 10/93 */
  948.                 document_section = string_downcase(document_section);        /* tung, 10/93 */
  949.                 if(strstr(document_section, word) != NULL)  {                /* tung, 10/93 */
  950.                   phrase_found = true;                                       /* tung, 10/93 */
  951.                   break;                                                     /* tung, 10/93 */
  952.                 }                                                            /* tung, 10/93 */
  953.               }                                                              /* tung, 10/93 */
  954.               if(phrase_found == false)                                      /* tung, 10/93 */
  955.                 internal_weight = 0.0;                                       /* tung, 10/93 */
  956.               phrase_found = false;                                          /* tung, 10/93 */
  957.             }
  958.             s_free(document_section);                                        /* tung, 10/93 */
  959.           }
  960.         }                                                               
  961. #endif /* LITERAL */
  962.  
  963. #ifdef BOOLEANS
  964.     if (gLastNot) {    
  965.        document_score_array[internal_document_id] = 0;
  966. /*  printf("search_word: boolean 'not' scored\n"); */
  967.         }
  968.      else 
  969. #endif /* BOOLEANS */
  970.     {
  971.     /* if(doc_id > 0) we are doing a relevant document */
  972. /*
  973. printf("wgt: %ld, internal weight: %lf, idf: %lf occurances: %ld\n",
  974.     wgt,internal_weight, idf,number_of_occurances);
  975. fflush(stdout);
  976. */
  977.         internal_weight*=idf; /* ses - for inverse doc. freq. */
  978. #ifndef BOOLEANS
  979.         document_score_array[internal_document_id] += 
  980.           (doc_id) ? (internal_weight * RF_WEIGHTING) : internal_weight;
  981. #else
  982. /* tung, 10/93 */
  983.         if(number_of_qwords == 0) {
  984.           document_score_array[internal_document_id] += 
  985.             (doc_id) ? (internal_weight * RF_WEIGHTING) : internal_weight;
  986.         }
  987.         else {
  988.           if((number_of_qwords > 0) && (search_result_array != NULL)) {
  989.             if(weight == LITERAL_FLAG) {
  990.               if(document_score_array[internal_document_id] > 0) {
  991.                 ((search_result_array[word_id]).doc_ids_array[phrase_count]).doc_id = internal_document_id;
  992.                 ((search_result_array[word_id]).doc_ids_array[phrase_count]).score +=
  993.                   (doc_id) ? (internal_weight * RF_WEIGHTING) : internal_weight;
  994.                 phrase_count++;
  995.                 search_result_array[word_id].number_of_hits = phrase_count;
  996.               }
  997.             }
  998.             else {
  999.               ((search_result_array[word_id]).doc_ids_array[count]).doc_id = internal_document_id;
  1000.               ((search_result_array[word_id]).doc_ids_array[count]).score +=
  1001.                 (doc_id) ? (internal_weight * RF_WEIGHTING) : internal_weight;
  1002.             }
  1003.           }
  1004.         }
  1005. #endif /* BOOLEANS */
  1006. /* tung, 10/93 */
  1007.         
  1008.         }
  1009. /*
  1010. printf("Score array: %lf\n",document_score_array[internal_document_id]);
  1011. fflush(stdout);
  1012. */
  1013.  
  1014.     i+=INDEX_ELEMENT_SIZE;
  1015.       }
  1016.     }
  1017.  
  1018. #ifdef PARTIALWORD
  1019.   index_file_block_number = 
  1020.     look_up_partialword_in_dictionary(NULL, &number_of_occurances, db);
  1021.   }
  1022. #endif /* PARTIALWORD */
  1023.  
  1024. /* tung, 10/93 */
  1025. #ifdef BOOLEANS
  1026.     if((number_of_qwords > 0) && (search_result_array != NULL)) {
  1027.       save_word_id(word_id);
  1028.       search_result_array[word_id].word_id = word_id;
  1029.       ++word_id;
  1030.     }
  1031. #endif /* BOOLEANS */
  1032. /* tung, 10/93 */
  1033.  
  1034. #ifdef BOOLEANS
  1035.    if(number_of_qwords == 0) {
  1036.     for (count=0; count < db->doc_table_allocated_entries; count++) {  
  1037.       if (!gLastAnd) {                                                  
  1038.         prev_score_array[count] = document_score_array[count];          
  1039.         }                                                               
  1040.       else {                                                            
  1041.         if ((document_score_array[count] == prev_score_array[count])    
  1042.             || (prev_score_array[count] == 0)) {
  1043.           document_score_array[count] = 0;                              
  1044.           prev_score_array[count] = 0;                                  
  1045.           }                                                             
  1046.         else {  
  1047.           prev_score_array[count] = document_score_array[count];        
  1048.           }                                                             
  1049.       }                                                                 
  1050.     }                                                                   
  1051.   /* if (gLastAnd) printf("search_word: boolean `and' scored\n"); */ 
  1052.   } 
  1053. #endif /* BOOLEANS */
  1054.  
  1055. #ifdef BOOLEANS
  1056.    gLastNot= gLastAnd= false;
  1057. #endif /* BOOLEANS */
  1058.     return(1); /* word present */
  1059. }
  1060.   
  1061.   else if(0 == index_file_block_number){
  1062.     /* an error occurred on looking up the word */
  1063. #ifdef BOOLEANS
  1064.    gLastNot= gLastAnd= false;
  1065. #endif  /* BOOLEANS */
  1066.     return(-1);
  1067.   }
  1068.   
  1069.   else {                /* index_file_block_number is negative */
  1070. #ifdef BOOLEANS
  1071. /* tung, 10/93 */
  1072.     if((number_of_qwords > 0) && (search_result_array != NULL)) {
  1073.       save_word_id(word_id);
  1074.       search_result_array[word_id].word_id = word_id;
  1075.       search_result_array[word_id].number_of_hits = 0;
  1076.       ++word_id;
  1077.     }
  1078. /* tung, 10/93 */
  1079.     else {
  1080.       if (gLastAnd) 
  1081.        for (count=0; count < db->doc_table_allocated_entries; count++) {
  1082.          document_score_array[count] = 0;                       
  1083.          prev_score_array[count] = 0;   
  1084.          } 
  1085.     }
  1086.    gLastNot= gLastAnd= false;
  1087. #endif  /* BOOLEANS */
  1088.     return(0);      /* word not present */
  1089.     }
  1090. }
  1091.  
  1092.  
  1093. /* now collect the best hits */
  1094. long finished_search_word(db)
  1095.      database *db;
  1096. #ifdef BOOLEANS
  1097.   long number_of_hits; /* tung, 10/93 */
  1098. #endif /* BOOLEANS */
  1099.  
  1100. #ifdef BOOL
  1101.   if (currentQuery != NULL)
  1102.     return; /* do nothing for boolean */
  1103. #endif /* def BOOL */
  1104.  
  1105. /* tung, 10/93 */
  1106. #ifdef BOOLEANS
  1107.   if((number_of_qwords > 0) && (search_result_array != NULL))
  1108.     number_of_hits = retriev_result(db->doc_table_allocated_entries);
  1109. #endif /* BOOLEANS */
  1110. /* tung, 10/93 */
  1111.  
  1112.   /* check the document_score_array */
  1113.   if(document_score_array_len < db->doc_table_allocated_entries)
  1114.     make_document_score_array(db->doc_table_allocated_entries);
  1115.  
  1116.   make_best_hits_array(max_hit_retrieved);
  1117.   sort_best_hits(db);
  1118.  syn_Free( db->syn_Table,&db->syn_Table_Size );
  1119.  
  1120.   return(0);
  1121. }
  1122.  
  1123.  
  1124.